////////////////////////////////////////////////
// DESCRIPTION:
//     Class implementationn for device driver
//     access to ISR information
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#include <windows.h>
#include <devload.h>
#include <winerror.h>
#include <pkfuncs.h>
#include <nkintr.h>
#include <RESMGR.H>
#include <FusionWare\DFX.h>

using namespace FusionWare;
using namespace FusionWare::DFX;

IrqInfo::IrqInfo()
{
    this->pIrqInfo = NULL;
    this->IrqInfoSize = 0;
    cbSize = sizeof(DDKIrqInfo);
    dwIrq = IRQ_UNSPECIFIED;
    dwSysintr = SYSINTR_UNDEFINED ;
    szIsrDll[0]=0;
    szIsrHandler[0]=0;
    this->EnableWake = FALSE;
    this->IrqMode = None;
    this->IrqState = 0;
    this->SysIntrRequested =FALSE;
}

IrqInfo::~IrqInfo()
{
    delete this->pIrqInfo;
}

BOOL IrqInfo::ReadRegValues(CRegKey& RootKey)
{
    DWORD valSize = 0;
    
    szIsrDll[0]=TCHAR('\0');
    szIsrHandler[0]=TCHAR('\0');

    if(!CRegValues::ReadRegValues(RootKey))
        return FALSE;
    
    // ISR DLL listed?
    if(szIsrDll[0]!=TCHAR('\0'))
    {
        if(szIsrHandler[0]==TCHAR('\0'))
        {
            // IsrHandler is required if an IsrDLL is used
            SetLastError(ERROR_INVALID_DATA);
            return FALSE;
        }

        valSize = RootKey.QueryValueSize(_T("IrqInfo"));
        this->pIrqInfo = new BYTE[valSize];
        if(this->pIrqInfo==NULL)
        {
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
            return FALSE;  
        }

        if(!RootKey.ReadValue(_T("IrqInfo"),this->pIrqInfo, valSize))
            return FALSE;

        this->IrqInfoSize = valSize;
    }
    return TRUE;
}

// If an IRQ is specified but no SYSINTR then 
// request a SYSINTR for the IRQ from the OAL
BOOL IrqInfo::RequestSysIntr()
{
    if(this->SysIntrRequested)
        return FALSE;

    BOOL retVal = TRUE;
    if(dwIrq!=IRQ_UNSPECIFIED && dwSysintr==SYSINTR_UNDEFINED)
    {
        retVal = DFX::RequestSysIntr(dwIrq,&dwSysintr);
        this->SysIntrRequested = retVal;
    }
    
    return retVal;
} 

// If a SYSINTR was assigned from the system
// release it.
//
// Note: 
//    Using this function it is not an error to release
//    if it wasn't allocated. This feature allows drivers
//    to blindly call ReleaseSysIntr on clean up.
//
BOOL IrqInfo::ReleaseSysIntr()
{
    if(!this->SysIntrRequested)
        return TRUE;

    BOOL retVal = DFX::ReleaseSysIntr(dwSysintr);
    
    // only mark it as unallocated if succesfully de-allocated
    this->SysIntrRequested = !retVal; 

    return retVal;
} 

 
BOOL IrqInfo::SysEnableWake(bool Enable)
{
    // set up the device to wake from suspend if requested
    if(this->EnableWake)
    {
        if(!KernelIoControl(Enable ? IOCTL_HAL_ENABLE_WAKE : IOCTL_HAL_DISABLE_WAKE, &dwSysintr, sizeof(dwSysintr),0,0,0))
        {
            ERRORMSG(1,(_T("Change Wake state failed. (0x%X)\r\n"), GetLastError()));
            return FALSE;
        }
    }
    return TRUE;
}

bool IrqInfo::InitIrq()
{
    // request a SYSINTR if not already provided
    if(!RequestSysIntr())
    {
        DEBUGMSG(TRUE, (_T("IrqInfo::IntIrq: RequestSysIntr failed! (0x%X)\r\n"), GetLastError()));
        return false;
    }

    // load the ISR chain handler, if any
    // this only returns FALSE if an ISR DLL is specified
    // but fails to load. All other cases return TRUE
    if(!IsrChainHandler.Load())
    {
        ERRORMSG(1, (TEXT("IrqInfo::IntIrq: Error loading ISR chain handler. (0x%X)\r\n"), GetLastError()));
        return false;
    }

    // set the IRQ mode for the device based on registry settings
    if(!SetIrqMode())
    {
        DEBUGMSG(TRUE, (_T("IrqInfo::IntIrq: SetIrqMode failed!\r\n")));
        return false;
    }

    // set up the device to wake from suspend if requested
    // This only returns FALSE if the wake is requested but it failed to set
    // the wake state. All other cases return TRUE.
    if(!SysEnableWake())
    {
        ERRORMSG(1, (TEXT("IrqInfo::IntIrq: Error Setting device wake source. (0x%X)\r\n"), GetLastError()));
        return false;
    }
}


